package com.sudo.service.admin.service.impl;

import com.sudo.common.constant.MenuConstant;
import com.sudo.common.enums.SysStatus;
import com.sudo.common.constant.UserConstant;
import com.sudo.common.utils.LocalDateTimeUtil;
import com.sudo.common.utils.RandomUtil;
import com.sudo.dao.admin.entity.SysButton;
import com.sudo.dao.admin.entity.SysMenu;
import com.sudo.dao.admin.entity.SysRoleButton;
import com.sudo.dao.admin.entity.SysRoleMenu;
import com.sudo.dao.admin.mapper.*;
import com.sudo.dao.admin.model.bo.SysMenuBO;
import com.sudo.dao.admin.model.vo.SimpleSysMenuVO;
import com.sudo.dao.admin.model.vo.SysMenuVO;
import com.sudo.service.admin.service.AdminBaseService;
import com.sudo.service.admin.service.SysMenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author 为道日损 2020-04-25 0:24
 */
@Service
public class SysMenuServiceImpl extends AdminBaseService implements SysMenuService {

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private SysMenuMapperCustom sysMenuMapperCustom;

    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Resource
    private SysButtonMapper sysButtonMapper;

    @Resource
    private SysRoleButtonMapper sysRoleButtonMapper;

    /**
     * 根据用户获取有权限的菜单
     * @param mailOrUsername 角色代码
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public List<SysMenu> queryMySysMenuByMailOrUsername(String mailOrUsername) {
        return sysMenuMapperCustom.findMyMenuByMailOrUsername(mailOrUsername);
    }

    /**
     * 获取所有的级联菜单
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public List<SysMenuVO> getCascadeSysMenuList() {
        return sysMenuMapperCustom.getCascadeSysMenuList(MenuConstant.MENU_ROOT_CODE);
    }

    /**
     * 通过menuCode获取菜单
     * @param menuCode 菜单code
     * @return 菜单
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysMenu getSysMenuByCode(String menuCode) {
        Example example = new Example(SysMenu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("mCode", menuCode);
        return sysMenuMapper.selectOneByExample(example);
    }

    /**
     * 获取简单的级联菜单（只有名称和code，pcode）
     * @return list
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public List<SimpleSysMenuVO> getSimpleCascadeSysMenuList(String menuCode, String status) {
        return sysMenuMapperCustom.getSimpleCascadeSysMenuList(menuCode,status);
    }

    /**
     * 查询根菜单和一二级菜单
     * @return list
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public List<SysMenuVO> getOneTwoCascadeSysMenuList() {
        List<SysMenuVO> sysMenuVOList = sysMenuMapperCustom.getCascadeSysMenuList(MenuConstant.MENU_ROOT_PCODE);
        Iterator<SysMenuVO> iterator = sysMenuVOList.iterator();
        while (iterator.hasNext()) {
            SysMenuVO sysMenuVO = iterator.next();
            List sysMenuList = sysMenuVO.getSysMenuList();

            Iterator<SysMenuVO> iterator1 = sysMenuList.iterator();
            while (iterator1.hasNext()) {
                SysMenuVO sysMenuVO1 = iterator1.next();
                List sysMenuList1 =sysMenuVO1.getSysMenuList();

                Iterator<SysMenuVO> iterator2 = sysMenuList1.iterator();
                while (iterator2.hasNext()) {
                    SysMenuVO sysMenuVO2 = iterator2.next();
                    //清除3级菜单内容
                    sysMenuVO2.setSysMenuList(null);
                }
            }

        }
        return sysMenuVOList;
    }

    /**
     * 根据id修改菜单
     * @param sysMenuBO sysMenuBo
     * @param sessionUser 当前session用户
     * @return int
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int updateSysMenuByCode(SysMenuBO sysMenuBO, String sessionUser) {
        //查询原始数据
        SysMenu oldSysMenu = getSysMenuByCode(sysMenuBO.getmCode());

        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyProperties(sysMenuBO, sysMenu,"mCode");
        String now = LocalDateTimeUtil.getStandardDateTimeStr();
        sysMenu.setUpdateBy(sessionUser);
        sysMenu.setUpdateTime(now);
        if (!SysStatus.ON.name().equals(sysMenu.getStatus())) {
            sysMenu.setStatus(SysStatus.OFF.name());
        }
        Example example = new Example(SysMenu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("mCode", sysMenuBO.getmCode());
        boolean isEqual = oldSysMenu.getStatus().equals(sysMenuBO.getStatus());
        int affectCount = sysMenuMapper.updateByExampleSelective(sysMenu, example);

        //====== redis ======
        if (affectCount > 0) {
            // 更新 redis_role_permission
            // 更新 redis_menu_button
            if (!isEqual) {
                List<SysRoleMenu> sysRoleMenuList = sysMenuMapperCustom.getRoleMenuByMenuCodeAndRoleStatus(
                        sysMenuBO.getmCode(), SysStatus.ON.name());
                if (SysStatus.ON.name().equals(sysMenuBO.getStatus())) {
                    //on
                    for (SysRoleMenu rm : sysRoleMenuList) {
                        onLoadAllRoleMenuButtonAuth(
                                rm.getRoleCode(),
                                rm.getMenuCode()
                        );
                    }
                    onLoadMenuButtonToRedis(sysMenuBO.getmCode());
                } else {
                    //off
                    for (SysRoleMenu rm : sysRoleMenuList) {
                        delRedisRolePermissionFromRedis(rm.getRoleCode(), rm.getMenuCode(),null);
                    }
                    ////delRedisMenuButtonFromRedis(sysMenuBO.getmCode(),null);
                }
            }
        }
        return affectCount;
    }

    /**
     * 添加菜单，同时需要将菜单权限添加到超级管理员
     * @param sysMenuBO 菜单
     * @param sessionUser 当前session用户
     * @return int
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int addSysMenu(SysMenuBO sysMenuBO, String sessionUser) {
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyProperties(sysMenuBO, sysMenu);
        String now = LocalDateTimeUtil.getStandardDateTimeStr();
        sysMenu.setCreateBy(sessionUser);
        sysMenu.setCreateTime(now);
        sysMenu.setStatus(sysMenuBO.getStatus());

        //添加菜单需要及时给超级管理员添加权限
        SysRoleMenu sysRoleMenu = new SysRoleMenu();
        sysRoleMenu.setMenuCode(sysMenu.getmCode());
        sysRoleMenu.setRoleCode(UserConstant.SUPER_ADMIN);
        sysRoleMenuMapper.insertSelective(sysRoleMenu);

        int affectCount = sysMenuMapper.insertSelective(sysMenu);

        //====== redis ======
        if (affectCount > 0 && SysStatus.ON.name().equals(sysMenuBO.getStatus())) {
            // redis_role_permission (新增超级管理员的权限)
            setRedisRolePermissionToRedis(
                    UserConstant.SUPER_ADMIN,
                    sysMenu.getmCode(),
                    UserConstant.NONE
            );
        }
        return affectCount;
    }

    /**
     * 根据menuCode删除菜单
     * @param menuCode 菜单代码
     * @return 删除行数
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int deleteSysMenuByCode(String menuCode) {
        Example example = new Example(SysMenu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("mCode", menuCode);

        //删除菜单下的按钮
        Example example1 = new Example(SysButton.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo("menuCode", menuCode);
        sysButtonMapper.deleteByExample(example1);

        //删除角色-菜单关联关系
        Example example2 = new Example(SysRoleMenu.class);
        Example.Criteria criteria2 = example2.createCriteria();
        criteria2.andEqualTo("menuCode",menuCode);
        sysRoleMenuMapper.deleteByExample(example2);

        //删除角色-菜单-按钮关联关系
        Example example3 = new Example(SysRoleButton.class);
        Example.Criteria criteria3 = example3.createCriteria();
        criteria3.andEqualTo("menuCode",menuCode);
        sysRoleButtonMapper.deleteByExample(example3);
        int affectCount = sysMenuMapper.deleteByExample(example);

        // ====== redis =======
        if (affectCount > 0) {
            // redis_role_permission (删除redis中角色-菜单对应的权限)
            List<SysRoleMenu> sysRoleMenuList = sysMenuMapperCustom.getRoleMenuByMenuCodeAndRoleStatus(
                    menuCode, null);
            for (SysRoleMenu rm : sysRoleMenuList) {
                delRedisRolePermissionFromRedis(rm.getRoleCode(),menuCode,null);
            }
            // redis_menu_button(删除redis中菜单-按钮权限)
            delRedisMenuButtonFromRedis(menuCode, null);
        }
        return affectCount;
    }

    /**
     *生成roleCode，严于律己，虽然生成相同的roleCode几率小得可怜，
     * 但墨菲定律告诉我们，只要发生一件事的几率存在，哪怕这种概率小得可怜，
     * 总有一天会发生
     */
    private void setMenuCode(SysMenu sysMenu){
        String menuCode = RandomUtil.getRandomStr(8);
        if (hasMenuCode(menuCode)) {
            setMenuCode(sysMenu);
        }else {
            sysMenu.setmCode(menuCode);
        }
    }

    /**
     * 判断数据库中是否已存在相同的 menuCode
     * @param menuCode 菜单Code
     * @return boolean
     */
    private boolean hasMenuCode(String menuCode){
        Example example = new Example(SysMenu.class);
        example.selectProperties("mCode");
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("mCode", menuCode);
        List<SysMenu> sysMenuList = sysMenuMapper.selectByExample(example);

        return !CollectionUtils.isEmpty(sysMenuList);
    }

    /**
     * 判断一个菜单是否含有子菜单
     * @param menuCode 菜单Code
     * @return boolean
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public boolean hasSubSysMenu(String menuCode) {
        Example example = new Example(SysMenu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("pCode", menuCode);
        List<SysMenu> sysMenuList = sysMenuMapper.selectByExample(example);
        return !CollectionUtils.isEmpty(sysMenuList);
    }

    //判断数据库中是否还有该菜单
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public boolean hasSysMenu(String menuCode) {
        Example example = new Example(SysMenu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("mCode", menuCode);
        List<SysMenu> sysMenuList = sysMenuMapper.selectByExample(example);
        return !CollectionUtils.isEmpty(sysMenuList);
    }

    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public boolean isSubMenuOrMyself(String menuCode, String OtherMenuCode) {
        if (menuCode.equals(OtherMenuCode)) {
            return true;
        }
        List<SimpleSysMenuVO> simpleSysMenuVOList = getSimpleCascadeSysMenuList(menuCode, null);
        List<String> menuCodeList = new ArrayList<>();
        getMenuCodeList(menuCodeList, simpleSysMenuVOList);
        return menuCodeList.contains(OtherMenuCode);
    }

    private void getMenuCodeList(List<String> menuCodeList, List<SimpleSysMenuVO> simpleSysMenuVOList) {
        for (SimpleSysMenuVO m: simpleSysMenuVOList) {
            menuCodeList.add(m.getmCode());
            List<SimpleSysMenuVO> simpleSysMenuVOList1 = m.getSimpleSysMenuVO();
            if (!CollectionUtils.isEmpty(simpleSysMenuVOList1)) {
                getMenuCodeList(menuCodeList,simpleSysMenuVOList1);
            }
        }
    }


    /**
     * 判断该菜单是否存在子菜单并且被移动
     * @param menuCode 菜单代码
     * @param OtherMenuCode 其他菜单代码
     * @return 布尔值
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public boolean isMoveSysMenu(String menuCode, String OtherMenuCode) {
        SysMenu sysMenu = getSysMenuByCode(menuCode);
        if (sysMenu != null) {
            if (sysMenu.getpCode().equals(OtherMenuCode)) {
                return false;
            }
        }
        return true;
    }


}
